package com.surfilter.risk.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.surfilter.risk.constant.ConstantStr;
import com.surfilter.risk.dto.BusinessSearchResult;
import com.surfilter.risk.dto.PunishSearchResult;
import com.surfilter.risk.dto.SearchCondition;
import com.surfilter.risk.entity.BusinessInfo;
import com.surfilter.risk.entity.Page;
import com.surfilter.risk.entity.PunishWithBLOBs;
import com.surfilter.risk.enums.CodeStateEnum;
import com.surfilter.risk.exception.ConditionTitleException;
import com.surfilter.risk.exception.QueryException;
import com.surfilter.risk.mapper.BusinessDetailsMapper;
import com.surfilter.risk.mapper.BusinessInfoMapper;
import com.surfilter.risk.mapper.PunishMapper;
import com.surfilter.risk.service.SearchService;
import com.surfilter.risk.utils.ElasticsearchUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * SearchServiceImpl
 * Dis:
 * Created by grom on 2017/5/15.
 */
@Service("searchService")
public class SearchServiceImpl implements SearchService{

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private static ResourceBundle bundle = ResourceBundle.getBundle("elasticsearch-config");
    private static String ES_INDEX = bundle.getString("es_index");
    private static String ES_TYPE_PINISH = bundle.getString("es_type_punish");
    private static String ES_TYPE_BUSINESSINFO = bundle.getString("es_type_businessInfo");
    private static String ES_TYPE_JUDGMENTDOCUMENTS = bundle.getString("es_type_judgmentDocuments");

    private static TransportClient transportClient;
    @Autowired
    private BusinessInfoMapper businessInfoMapper;
    @Autowired
    private PunishMapper punishMapper;
    @Autowired
    private BusinessDetailsMapper businessDetailsMapper;
    /**
     * 搜索接口数据
     * @param stitle
     * @param pageNo
     * @param pageSize
     * @param scope
     * @param trade
     * @param position
     * @param compstate
     * @param type
     * @return
     */
    @Transactional
    @Override
    public String search(String stitle,
                         Integer pageNo, Integer pageSize,
                         String scope, String trade, String position, String compstate,
                         String type) {
        long startTime = new Date().getTime();
        transportClient = ElasticsearchUtils.init();
        //result   data
        Map<String, Object> result = Maps.newHashMap();
        List data = Lists.newArrayList();
        try {
            if(null == stitle){
                //没有查询内容
                logger.warn("没有查询关键词，默认查询所有企业");
                throw new ConditionTitleException("Query condition(stitle) is empty");
            }
            if(null == type){
                //没有查询类型
                logger.warn("没有查询类型，默认查询企业");
                type = ConstantStr.TYPE_OF_COMP;
            }
            //将搜索关键词拆分
            String [] keyWords;
            if(stitle.contains(" ")){
                keyWords = stitle.split("\\s+");
            }else{
                keyWords = new String[]{stitle};
            }
            //搜索条件获取
            Map scopeMap = Maps.newHashMap();
            Map tradeMap = Maps.newHashMap();
            Map positionMap = Maps.newHashMap();
            Map compstateMap = Maps.newHashMap();
                long comCountStartTime = new Date().getTime();
            comConditionCount(ES_INDEX,ES_TYPE_BUSINESSINFO,tradeMap,positionMap,compstateMap,keyWords);
                long comCountEndTime = new Date().getTime();
                logger.info("工商统计耗时 " + (comCountEndTime - comCountStartTime));
                long punishCountStartTime = new Date().getTime();
            punishConditionCount(ES_INDEX,ES_TYPE_PINISH,scopeMap,keyWords);
                long punishCountEndTime = new Date().getTime();
                logger.info("惩戒统计耗时 " + (punishCountEndTime - punishCountStartTime));

            //查询相关内容并分页
            Page page = null;
            if(ConstantStr.TYPE_OF_COMP.equals(type)){
                    long pageStartTime = new Date().getTime();
                page = findCompanyByPage(keyWords,trade,position,compstate,pageSize,pageNo,ES_INDEX,ES_TYPE_BUSINESSINFO);
                    long pageEndTime = new Date().getTime();
                    logger.info("工商分页统计耗时 " + (pageEndTime - pageStartTime));
                    long page2StartTime = new Date().getTime();
                page = transfer2BusinessSearchResult(page);
                    long page2EndTime = new Date().getTime();
                    logger.info("工商转换查询惩戒数量统计耗时 " + (page2EndTime - page2StartTime));
            }else if(ConstantStr.TYPE_OF_CASE.equals(type)){
                page = findPunishByPage(keyWords,scope,pageSize,pageNo,ES_INDEX,ES_TYPE_PINISH);
                page = transfer2PunishSearchResult(page);
            }
            //只有一个Client的对象，一旦关闭，出现 transport client is closed的错误
//                esClose();
            data = page.getList();
            result.put(ConstantStr.CODE, CodeStateEnum.SUCCESS);
            result.put(ConstantStr.PAGESIZE, pageSize);
            result.put(ConstantStr.PAGE_NUMBER, page.getPageNumber());
            result.put(ConstantStr.TOTAL_PAGE, page.getTotalPage());
            result.put(ConstantStr.TOTAL_ROW, page.getTotalRow());

            //搜索分类信息
            result.put("scope",transfer2SearchCondition(scopeMap));
            result.put("trade",transfer2SearchCondition(tradeMap));
            result.put("position",transfer2SearchCondition(positionMap));
            result.put("compstate",transfer2SearchCondition(compstateMap));
        }catch (ConditionTitleException e1){
            throw e1;
        }catch (Exception e){
            logger.error(e.getMessage(),e);
            result.put(ConstantStr.CODE, CodeStateEnum.FAIL);
            result.put(ConstantStr.MSG, e.getMessage());
            //所有的编译时异常，转化为运行时异常（运行时异常，spring可以做rollback的操作）
            throw new QueryException("Query inner error : "+ e.getMessage());
        }
        result.put(ConstantStr.DATA, data);
        long endTime = new Date().getTime();
            logger.info("统计总计耗时 " + (endTime - startTime));
        result.put("sec",(endTime - startTime)/1000.0);
        return new Gson().toJson(result);
    }

    public List<SearchCondition> transfer2SearchCondition(Map<Object,Object> map){
        List<SearchCondition> result = Lists.newArrayList();
        if(null != map && map.size()>0){
            for(Map.Entry entry : map.entrySet()){
                SearchCondition searchCondition = new SearchCondition((String) entry.getKey(), (Long) entry.getValue());
                result.add(searchCondition);
            }
        }
        return result;
    }
    /**
     * 通过工商信息，获取其他三行搜索条件
     */
    public void comConditionCount(String index, String type,
                                  Map tradeMap,
                                  Map positionMap,
                                  Map compstateMap,
                                  String ... keyWords){

        //增加特定字段的统计
        AggregationBuilder tradeAggregationBuilder = AggregationBuilders.terms("tradeListSum")
                .field("industryType")
                .size(Integer.MAX_VALUE);
        AggregationBuilder positionAggregationBuilder = AggregationBuilders.terms("positionListSum")
                .field("provence")
                .size(Integer.MAX_VALUE);
        AggregationBuilder compstateAggregationBuilder = AggregationBuilders.terms("compstateListSum")
                .field("businessStatus")
                .size(Integer.MAX_VALUE);

        SearchRequestBuilder searchRequestBuilder = transportClient.prepareSearch(index);
        // 设置查询索引类型,setTypes("productType1", "productType2","productType3");
        // 用来设定在多个类型中搜索
        searchRequestBuilder.setTypes(type);
        //多条件
        // TODO: 2017/5/17
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(null == keyWords || "[]".equals(Arrays.toString(keyWords))){
            //关键词为空。查询所有
            boolQueryBuilder.should(QueryBuilders.matchAllQuery());
        }else{
            for(int i=0;i<keyWords.length;i++){
                boolQueryBuilder
                        .should(QueryBuilders.termQuery("ename", keyWords[i]))
                        .should(QueryBuilders.termQuery("businessScope", keyWords[i]))
                        .should(QueryBuilders.termQuery("address", keyWords[i]));
            }
        }
        searchRequestBuilder
                .setQuery(boolQueryBuilder);

        //精确查询
        searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
        searchRequestBuilder
                .addAggregation(tradeAggregationBuilder)
                .addAggregation(positionAggregationBuilder)
                .addAggregation(compstateAggregationBuilder);
        // 执行搜索,返回搜索响应信息
        SearchResponse response = searchRequestBuilder.execute()
                .actionGet();

        Terms tradeTerms = response.getAggregations().get("tradeListSum");
        Terms positionTerms = response.getAggregations().get("positionListSum");
        Terms compstateTerms = response.getAggregations().get("compstateListSum");

        Map searchConditionMap = getSearchCondition(tradeTerms);
        Map authorityRelationshipMap = getIndustryRelationship(businessInfoMapper.selectIndustry());
        tradeMap.putAll(transfer2ScopeTradeMap(searchConditionMap, authorityRelationshipMap));

        positionMap.putAll(getSearchCondition(positionTerms));
        compstateMap.putAll(getSearchCondition(compstateTerms));

//        client.close();
    }

    /**
     * 通过惩戒信息查询搜索条件
     */
    public void punishConditionCount(String index, String type,
                                     Map scopeMap,
                                     String ... keyWords){

        //增加特定字段的统计
        AggregationBuilder scopeAggregationBuilder = AggregationBuilders.terms("scopeListSum")
                .field("authorityType")
                .size(Integer.MAX_VALUE);

        SearchRequestBuilder searchRequestBuilder = transportClient.prepareSearch(index);
        // 设置查询索引类型,setTypes("productType1", "productType2","productType3");
        // 用来设定在多个类型中搜索
        searchRequestBuilder.setTypes(type);
        //多条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(null == keyWords || "[]".equals(Arrays.toString(keyWords))){
            //关键词为空。查询所有
            boolQueryBuilder.should(QueryBuilders.matchAllQuery());
        }else{
            for(int i=0;i<keyWords.length;i++){
                boolQueryBuilder
                        .should(QueryBuilders.termQuery("administrativePeople", keyWords[i]))
                        .should(QueryBuilders.termQuery("punishAuthority", keyWords[i]))
                        .should(QueryBuilders.termQuery("punishName", keyWords[i]));
            }
        }
        searchRequestBuilder
                .setQuery(boolQueryBuilder);
        //精确查询
        searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
        searchRequestBuilder
                .addAggregation(scopeAggregationBuilder);
        // 执行搜索,返回搜索响应信息
        SearchResponse response = searchRequestBuilder.execute()
                .actionGet();
        //命中情况
//        System.out.println(response.getHits());
        Terms scopeTerms = response.getAggregations().get("scopeListSum");
        //行政单位为数字、需要更改映射
        Map searchConditionMap = getSearchCondition(scopeTerms);
        Map authorityRelationshipMap = getAuthorityRelationship( punishMapper.selectUnit());
        scopeMap.putAll(transfer2ScopeTradeMap(searchConditionMap, authorityRelationshipMap));
//        client.close();
    }

    /**
     * 获取工商的分页信息
     */
    public Page findCompanyByPage(String [] keyWords,
                           String trade, String position, String compstate,
                           Integer pageSize, Integer pageNo,
                           String index,String type){
        // TODO: 2017/5/18 判断有误
        if(null == keyWords || "[]".equals(Arrays.toString(keyWords))){
            //关键词为空。查询所有
            return ElasticsearchUtils.findByPageWithHightLight(index, type, QueryBuilders.matchAllQuery()
                    , BusinessInfo.class, pageSize, pageNo);
        }else{
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            for(int i=0;i<keyWords.length;i++){
                // TODO: 2017/5/17 0017  需要增加其他分词字段的匹配
                boolQueryBuilder
                        .should(QueryBuilders.termQuery("ename", keyWords[i]))
                        .should(QueryBuilders.termQuery("businessScope", keyWords[i]))
                        .should(QueryBuilders.termQuery("address", keyWords[i]));
            }
            if(null != trade){
                boolQueryBuilder.should(QueryBuilders.termQuery("industryType", trade));
            }
            if(null != position){
                boolQueryBuilder.should(QueryBuilders.termQuery("provence", position));
            }
            if(null != compstate){
                boolQueryBuilder.should(QueryBuilders.termQuery("businessStatus", compstate));
            }
            return ElasticsearchUtils.findByPageWithHightLight(index, type, boolQueryBuilder, BusinessInfo.class, pageSize, pageNo);
        }
    }

    /**
     * 获取惩戒的分页信息
     */
    public Page findPunishByPage(String [] keyWords,
                          String scope,
                          Integer pageSize, Integer pageNo,
                          String index,String type){
        if(null == keyWords || "[]".equals(Arrays.toString(keyWords))){
            //关键词为空。查询所有
            return ElasticsearchUtils.findByPageWithHightLight(index, type, QueryBuilders.matchAllQuery()
                    , PunishWithBLOBs.class, pageSize, pageNo);
        }else{
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            for(int i=0;i<keyWords.length;i++){
                boolQueryBuilder
                        .should(QueryBuilders.termQuery("administrativePeople", keyWords[i]))
                        .should(QueryBuilders.termQuery("punishAuthority", keyWords[i]))
                        .should(QueryBuilders.termQuery("punishName", keyWords[i]));
            }
            if(null != scope){
                boolQueryBuilder.should(QueryBuilders.termQuery("authorityType", scope));
            }
            return ElasticsearchUtils.findByPageWithHightLight(index, type, boolQueryBuilder, PunishWithBLOBs.class, pageSize, pageNo);
        }
    }
    /**
     * 转换成案件搜索结果的DTO
     */
    private Page transfer2PunishSearchResult(Page page) {
        List<PunishWithBLOBs> punishList = page.getList();
        List<PunishSearchResult> result = Lists.newArrayList();
        for(PunishWithBLOBs punish : punishList){
            PunishSearchResult punishSearchResult = new PunishSearchResult();
            punishSearchResult.setId(punish.getId());
            punishSearchResult.setTitle(punish.getPunishName());
            punishSearchResult.setCasenumber(punish.getAdministrativePunishId());
            // TODO: 2017/5/18 改成将查询出来的内容存放在map里面，减少查询次数
            punishSearchResult.setCourt(punishMapper.selectOneUnit(punish.getAuthorityType()));//去admin_unit里面查
            punishSearchResult.setJudgetime(punish.getDecisionDate());
            punishSearchResult.setType(punish.getPunishType());
            result.add(punishSearchResult);
        }
        page.getList().clear();
        page.getList().addAll(result);
        return page;
    }
    /**
     * 转换成企业搜索结果的DTO
     */
    private Page transfer2BusinessSearchResult(Page page) {
        List<BusinessInfo> businessInfoList = page.getList();
        if(null != businessInfoList && businessInfoList.size()>0){
            List<BusinessSearchResult> result = Lists.newArrayList();
            for(BusinessInfo businessInfo : businessInfoList){
                BusinessSearchResult businessSearchResult = new BusinessSearchResult();
                businessSearchResult.setId(businessInfo.getId());
                businessSearchResult.setAddress(businessInfo.getAddress());
                businessSearchResult.setCompany(businessInfo.getEname());
                businessSearchResult.setCorporation(businessInfo.getLegalRep());
                businessSearchResult.setRecapital(businessInfo.getRegCaptial());
                //股票代码目前没有
//            businessSearchResult.setShare();
                //成立年限 issueTime--营业开始日期
                if(null != businessInfo.getIssueTime()){
                    businessSearchResult.setSetupyear(new Date().getYear() - businessInfo.getIssueTime().getYear());
                }
                //查询数量
                Integer punishNum = businessInfoMapper.getPunishNum(businessInfo.getId());
                businessSearchResult.setNum(punishNum == null? 0:punishNum);

                Integer riskNum = ((Long) businessDetailsMapper.findRiskRatio(businessInfo.getId()).get("riskratio")).intValue();
                businessSearchResult.setRisk(riskNum);
                result.add(businessSearchResult);
            }
            page.getList().clear();
            page.getList().addAll(result);
        }
        return page;
    }
    /**
     * 行政单位和行业类别的id和name之间需要进行转换
     */
    public Map transfer2ScopeTradeMap(Map<Object, Object> conditionMap, Map map){
        Map result = Maps.newHashMap();
        for(Map.Entry entry : conditionMap.entrySet()){
            Long id = (Long)entry.getKey();
            Long num = (Long)entry.getValue();
            String key;
            if(null == id){
                key = "未知";
            }else if(0 == id){
                key = "未知";
            }else{
                key = (String) map.get(id.intValue());
            }
            result.put(key, num);
        }
        return result;
    }
    /**
     * 将查询到的行政单位id和name从list中取出存放在map中
     */
    private Map getAuthorityRelationship(List<Map> list){
        Map mapResult = Maps.newHashMap();
        try {
            if(null != list) {
                for (Map map : list) {
                    mapResult.put(map.get("unit_id"), map.get("unit_name"));
                }
            }else{
                throw new Exception("查询行业分类异常");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mapResult;
    }
    /**
     * 将查询到的行业类别id和name从list中取出存放在map中
     */
    private Map getIndustryRelationship(List<Map> list){
        Map mapResult = Maps.newHashMap();
        try {
            if(null != list) {
                for (Map map : list) {
                    mapResult.put(map.get("industry_id"), map.get("industry_name"));
                }
            }else{
                throw new Exception("查询行业分类异常");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mapResult;
    }
    /**
     * 将统计结果以map形式返回
     */
    public Map getSearchCondition (Terms terms){
        Map map = Maps.newHashMap();
        if (terms != null) {
            for (Terms.Bucket entry : terms.getBuckets()) {
                map.put(entry.getKey(), entry.getDocCount());
            }
        }
        return map;
    }
}
